﻿// Copyright (c) Microsoft Corporation. All rights reserved. See License.txt in the project root for license information.
//
// LoadPage.xaml.cpp
// Implementation of the LoadPage class
//

#include "pch.h"
#include "LoadPage.xaml.h"

using namespace Weathr;

using namespace concurrency;
using namespace Platform;
using namespace std;
using namespace Windows::ApplicationModel::Activation;
using namespace Windows::Foundation;
using namespace Windows::Foundation::Collections;
using namespace Windows::UI::Core;
using namespace Windows::UI::Xaml;
using namespace Windows::UI::Xaml::Controls;
using namespace Windows::UI::Xaml::Controls::Primitives;
using namespace Windows::UI::Xaml::Data;
using namespace Windows::UI::Xaml::Input;
using namespace Windows::UI::Xaml::Interop;
using namespace Windows::UI::Xaml::Media;
using namespace Windows::UI::Xaml::Navigation;

LoadPage::LoadPage(SplashScreen^ splashScreen, const function<void ()>& navigatePredicate, const function<task<void> ()>& asyncLoadFunction, shared_ptr<ExceptionPolicy> exceptionPolicy) : m_exceptionPolicy(exceptionPolicy)
{
    InitializeComponent();

    // Listen for window resize events to reposition the extended splash screen image accordingly.
    // This is important to ensure that the extended splash screen is formatted properly in response to snapping, unsnapping, rotation, etc...
    m_windowSizeEventToken = Window::Current->SizeChanged += ref new WindowSizeChangedEventHandler(this, &LoadPage::OnResize);

    m_splash = splashScreen;
    if (m_splash != nullptr)
    {
        // Register an event handler to be executed when the splash screen has been dismissed.
        m_splash->Dismissed += ref new TypedEventHandler<SplashScreen^, Object^>(this, &LoadPage::DismissedEventHandler);

        // Retrieve the window coordinates of the splash screen image.
        m_splashImageRect = m_splash->ImageLocation;
        PositionImage();
    }

    // Load the app state in the background and then wait for the splash screen to be dismissed.
    asyncLoadFunction().then([this]()
    {
        assert(IsBackgroundThread());
        // The previous state is loaded. Now wait for the app to be ready to display the initial page.
        m_dismissed.wait();

    }, task_continuation_context::use_arbitrary()).then([this, navigatePredicate]()
    {
        assert(IsMainThread());

        // Unsubscribe from the SizeChanged event to prevent DisconnectedException when the 
        // app is resized or its orientation changes.
        Window::Current->SizeChanged -= m_windowSizeEventToken;

        // Call the predicate function, which is expected to navigate to the main page.
        navigatePredicate();

    }, task_continuation_context::use_current());
}

void LoadPage::PositionImage()
{
    Canvas::SetTop(ExtendedSplashImage, m_splashImageRect.Y);
    Canvas::SetLeft(ExtendedSplashImage, m_splashImageRect.X);
    ExtendedSplashImage->Height = m_splashImageRect.Height;
    ExtendedSplashImage->Width = m_splashImageRect.Width;

    Progress->SetValue(Canvas::LeftProperty,  m_splashImageRect.X + ExtendedSplashImage->Width/2 - Progress->Width/2);
    Progress->SetValue(Canvas::TopProperty,  m_splashImageRect.Bottom + 20);
}

// Called when the system has transitioned from the splash screen to the extended splash screen (application's first view).
void LoadPage::DismissedEventHandler(SplashScreen^ sender, Object^ e)
{
    // Set the event to signal to the background loading task that the app is ready to display the initial page.
    m_dismissed.set();
}

void LoadPage::OnResize(Object^ sender, WindowSizeChangedEventArgs^ e)
{
    // Safely update the extended splash screen image coordinates. This function will be executed in response to snapping, unsnapping, rotation, etc...
    if (m_splash != nullptr)
    {
        // Update the coordinates of the splash screen image.
        m_splashImageRect = m_splash->ImageLocation;
        PositionImage();
    }
}